#include <sstream>
#include "vl_map_prop.h"
#include "vl_node_prop.h"
#include "vl_array_prop.h"

using namespace VL;

/**
 * @Author: CimZzz
 * @Date: 2022-06-21 15:46:14
 * 
 * 供 RootProp 使用的构造方法
 */
MapProp::MapProp(VLProp::PropType type): VLProp(type) {

}

/**
 * @Author: CimZzz
 * @Date: 2022-06-21 15:46:14
 * 
 * 构造方法
 */
MapProp::MapProp(): VLProp(VLProp::PropType::Map) {

}



/**
 * @Author: CimZzz
 * @Date: 2022-06-21 15:46:29
 * 
 * 构造方法
 * @param name 属性名
 */
MapProp::MapProp(std::string name): VLProp(VLProp::PropType::Map) {
	this->setName(name);
}


/**
 * @Author: CimZzz
 * @Date: 2022-06-16 20:13:24
 * 
 * 获取子节点
 * 
 * @param name 节点名
 * 
 * @return 子节点, 如果不存在则会返回空节点
 */
std::shared_ptr<VLProp> MapProp::operator [](const std::string& name) {
	return this->get(name);
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-10 16:05:01
 * 
 * 获取子节点
 * 
 * @param name 节点名
 * 
 * @return 子节点, 如果不存在则会返回空节点
 */
std::shared_ptr<VLProp> MapProp::get(const std::string& name) {
	auto iter = this->children.find(name);
	if(iter != this->children.end()) {
		return iter->second;
	}
	return std::shared_ptr<VLProp>(new VLProp(VLProp::PropType::Empty));
}


/**
 * @Author: CimZzz
 * @Date: 2022-06-16 20:13:24
 * 
 * 设置子节点, 直接设置节点值
 * 
 * @param name 节点名
 * @param value 节点值
 */
void MapProp::operator ()(const std::string& name, const std::string& value) {
	this->push(name, value);
}

/**
 * @Author: CimZzz
 * @Date: 2022-06-16 20:13:24
 * 
 * 设置子节点
 * 
 * @param name 节点名
 * @param prop 节点指针
 */
void MapProp::operator ()(const std::string& name, VLProp* prop) {
	this->push(name, prop);
}

/**
 * @Author: CimZzz
 * @Date: 2022-06-16 20:13:24
 * 
 * 设置子节点
 * 
 * @param name 节点名
 * @param prop 节点智能指针
 */
void MapProp::operator ()(const std::string& name, const std::shared_ptr<VLProp>& prop) {
	this->push(name, prop);
}


/**
 * @Author: CimZzz
 * @Date: 2022-08-10 16:09:02
 * 
 * 设置子节点
 * 
 * @param name 节点名
 * @param value 节点值
 */
void MapProp::push(const std::string& name, const std::string& value) {
	NodeProp* prop = new NodeProp();
	prop->setName(name);
	prop->setValue(value);
	this->children[name] = std::shared_ptr<VLProp>(prop);
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-10 16:10:10
 * 
 * 设置子节点
 * 
 * @param name 节点名
 * @param prop 节点指针
 */
void MapProp::push(const std::string& name, VLProp* prop) {
	if(prop == nullptr || prop->getType() == VLProp::PropType::Empty) {
		return;
	}
	prop->setName(name);
	this->children[name] = std::shared_ptr<VLProp>(prop);
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-10 16:17:03
 * 
 * 设置子节点
 * 
 * @param name 节点名
 * @param prop 节点智能指针
 */
void MapProp::push(const std::string& name, const std::shared_ptr<VLProp>& prop) {
	if(prop.get() == nullptr || prop->getType() == VLProp::PropType::Empty) {
		return;
	}
	prop->setName(name);
	this->children[name] = prop;
}


/**
 * @Author: CimZzz
 * @Date: 2022-06-21 15:25:58
 * 
 * 删除指定属性名元素
 * 
 * @param name 属性名
 * 
 * @return 当前映射表引用属性
 */
MapProp& MapProp::operator -(const std::string& name) {
	this->remove(name);
	return *this;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-10 16:21:09
 * 
 * 删除指定属性名元素
 * 
 * @param name 属性名
 * 
 * @return 当前映射表引用属性
 */
void MapProp::remove(const std::string& name) {
	auto iter = this->children.find(name);
	if(iter != this->children.end()) {
		this->children.erase(iter);
	}
}

/**
 * @Author: CimZzz
 * @Date: 2022-07-13 14:48:07
 * 
 * 遍历 Map
 * @param func 遍历函数
 */
void MapProp::foreach(ForEachFunc func) {
	if(func) {
		for(auto iter = this->children.begin() ; iter != this->children.end() ; iter ++) {
			if(!func(iter->first, iter->second)) {
				break;
			}
		}
	}
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-25 20:08:16
 * 
 * 克隆当前属性
 * 
 * @return 属性指针
 */
VLProp* MapProp::clone() {
	MapProp* mapProp = new MapProp;
	for(auto iter = this->children.begin() ; iter != this->children.end() ; iter ++) {
		auto key = iter->first;
		auto propPtr = iter->second;
		if(propPtr->isContainer()) {
			mapProp->push(key, propPtr->clone());
		} else {
			mapProp->push(key, propPtr);
		}
	}
	return mapProp;
}


/**
 * @Author: CimZzz
 * @Date: 2022-06-30 19:14:40
 * 
 * 组合属性
 * @param prop 属性指针
 * 
 * @return 组合成功返回 false
 */
bool MapProp::combine(std::shared_ptr<VLProp>& prop) {
	// MapProp 可以和 Node、MapProp 类型进行合并
	// 如果 Node 和 Node 合并, Node 会提升为 ArrayProp
	// 如果 Node 和 Array 合并, Node 会复制一份 ArrayProp, 并把当前的 Prop 添加到新的 ArrayProp 中
	// 如果 Node 没有 Name, 则忽略
	// 空节点默认为合并成功
	if(prop == nullptr || prop->isEmpty()) {
		return true;
	}

	if(!prop->isNode() && !prop->isMap()) {
		return false;
	}

	if(prop->isNode()) {
		if(prop->getName().empty()) {
			return true;
		}

		auto existProp = this->get(prop->getName());
		if(existProp->isEmpty()) {
			// 节点不存在, 直接放到 Map 中
			this->push(prop->getName(), prop);
			return true;
		}
		if(existProp->isNode()) {
			// 节点同为 Node, 组合成 ArrayProp
			std::shared_ptr<ArrayProp> arrayProp(new ArrayProp);
			(*arrayProp)(existProp);
			(*arrayProp)(prop);
			this->push(prop->getName(), arrayProp);
			return true;
		}
		if(existProp->isArray()) {
			return existProp->combine(prop);
		}
		if(existProp->isMap()) {
			// 不能为 Map
			return false;
		}
		return true;
	}

	if(prop->isMap()) {
		auto mapProp = std::static_pointer_cast<MapProp, VLProp>(prop);
		for(auto iter = mapProp->children.begin() ; iter != mapProp->children.end() ; iter ++) {
			auto key = iter->first;
			auto propPtr = iter->second;
			auto existProp = this->get(key);
			if(existProp->isEmpty()) {
				// 空属性直接设置
				if(propPtr->isContainer()) {
					this->push(key, propPtr->clone());
				} else {
					this->push(key, propPtr);
				}
				
				continue;
			}


			if(existProp->isNode()) {
				if(propPtr->isNode()) {
					// 节点同为 Node, 组合成 ArrayProp
					std::shared_ptr<ArrayProp> arrayProp(new ArrayProp);
					(*arrayProp)(existProp);
					(*arrayProp)(propPtr);
					this->push(key, arrayProp);
					continue;
				}
				if(propPtr->isArray()) {
					// 节点同为 Node, 组合成 ArrayProp
					std::shared_ptr<ArrayProp> arrayProp(new ArrayProp(*((ArrayProp*) propPtr.get())));
					(*arrayProp)(existProp);
					this->push(key, arrayProp);
					continue;
				}
				if(propPtr->isMap()) {
					// 不能为 Map
					return false;
				}
				continue;
			}
			
			if(existProp->isMap()) {
				if(!propPtr->isMap()) {
					// 只能为 Map
					return false;
				}

				if(!existProp->combine(propPtr)) {
					// Map 与 Map 合并失败
					return false;
				}

				continue;
			}
			
			if(existProp->isArray()) {
				if(!existProp->combine(propPtr)) {
					// Array 内部合并失败
					return false;
				}
				continue;
			}
		}
	}	

	return true;
}

/**
 * @Author: CimZzz
 * @Date: 2022-07-04 17:55:29
 * 
 * 获取当前尺寸
 * @return 当前尺寸
 */
unsigned int MapProp::size() {
	return this->children.size();
}

/**
 * @Author: CimZzz
 * @Date: 2022-06-21 15:57:31
 * 
 * 清空全部属性
 */
void MapProp::clear() {
	this->children.clear();
}


/**
 * @Author: CimZzz
 * @Date: 2022-06-30 18:22:06
 * 
 * 比较两个 Array 之间的区别
 * @param prop 属性指针
 * @return 如果相同返回 true
 */
bool MapProp::diff(VLProp* prop) {
	if(prop == nullptr || (prop->getType() != VLProp::PropType::Root && prop->getType() != VLProp::PropType::Map)) {
		return false;
	}

	MapProp* mapProp = (MapProp*) prop;
	if(this->size() != mapProp->size())  {
		return false;
	}
	for(auto iter = this->children.begin() ; iter != this->children.end() ; iter ++) {
		auto otherProp = (*mapProp)[iter->first];
		if(!iter->second->diff(otherProp)) {
			return false;
		}
	}

	return true;
}

/**
 * @Author: CimZzz
 * @Date: 2022-06-21 11:04:46
 * 
 * 构建属性打印信息
 */
std::string MapProp::buildPropPrintInfo() {
	std::stringstream stream;
	stream << "(";
	if(this->getName() != "") {
		stream << "name: " << this->getName() << ", ";
	}
	stream << "size: " << this->children.size();
	stream << ")";
	return stream.str();
}

/**
 * @Author: CimZzz
 * @Date: 2022-06-21 15:16:41
 * 
 * 打印属性节点信息, 设置前缀
 * @param prefix 前缀
 */
void MapProp::printWithPrefix(std::string prefix) {
	VLProp::printWithPrefix(prefix);
	std::string childPrefix = "\t" + prefix;
	for(auto i = this->children.begin() ; i != this->children.end() ; i ++) {
		i->second->printWithPrefix(childPrefix);
	}
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-19 18:10:42
 * 
 * 获取 Map 的起始迭代器
 * 
 * @return Map 的起始迭代器
 */
std::map<std::string, std::shared_ptr<VLProp>>::iterator MapProp::begin() {
	return this->children.begin();
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-19 18:10:42
 * 
 * 获取 Map 的终止迭代器
 * 
 * @return Map 的终止迭代器
 */
std::map<std::string, std::shared_ptr<VLProp>>::iterator MapProp::end() {
	return this->children.end();
}